﻿#region License
// /* **************************************************************
// * Copyright (C) intex Consulting GmbH - All Rights Reserved    *
// *--------------------------------------------------------------*
// * Unauthorized copying of this file, via any medium is         *
// * strictly prohibited                                          *
// *--------------------------------------------------------------*
// * Proprietary and confidential                                 *
// *--------------------------------------------------------------*
// * Dissasembling/modifications strictly prohibited!             *
// ***************************************************************/
#endregion

using System;
using System.Collections.Generic;
using System.Text;
using ComHlp.ContentClasses;
using ComHlp.ContentClasses.VirtualControls;
using ComHlp.ContentClasses.VirtualControls.Buttons;
using ComHlp.ContentClasses.VirtualControls.ContextMenu;
using ComHlp.ContentClasses.VirtualControls.Gauges;
using ComHlp.ContentClasses.VirtualControls.Polynom;
using ComHlp.enums;
using ComHlp.enums.Fields;

namespace ComHlp.Classes.Parser.Supplementary
{
    /// <summary> Parser for the graphics area of the formdef </summary>
    internal static class GraphicsParser
    {
        /// <summary> Split the graphics area </summary>
        /// <param name="recvStr"></param>
        /// <returns></returns>
        public static MapGraphics SplitGraphicArea(string recvStr)
        {
            // elementcount + 5 chars trash
            StringBuilder sbRecvStr = new StringBuilder(recvStr);
            int elementCount = ParseHelper.String2Int(sbRecvStr.ToString(0, 4));
            sbRecvStr.Remove(0, 9);

            ButtonParseHelper buttonParseHelper = new ButtonParseHelper();

            // init return val
            MapGraphics mapGraphics = new MapGraphics();

            for (int i = 0; i < elementCount; i++)
            {
                // fix to prevent crashes for not implemented functions
                if (sbRecvStr.Length < 5)
                    break;

                // length of element
                int elementLength = ParseHelper.String2Int(sbRecvStr.ToString(0, 5));
                sbRecvStr.Remove(0, 5);
                elementLength -= 5;

                // type
                switch (sbRecvStr.ToString(0, 4))
                {
                    case "KOME":
                        // got context menue - we only should get here once
                        if (mapGraphics.ContextMenu == null)
                            mapGraphics.ContextMenu = new ItxContextMenu();

                        // remove identifier
                        sbRecvStr.Remove(0, 4);
                        elementLength -= 4;
                        ParseContextMenu(sbRecvStr, mapGraphics, elementLength);
                        continue;
                    case "BMP ":
                        // remove identifier
                        sbRecvStr.Remove(0, 4);
                        ParseBitmap(sbRecvStr, mapGraphics);
                        continue;
                    case "BUTT":
                        //{00100BUTT10801380    12423300          R5  00FC      ENT     V                7018    V    = Versand}
                        //{     BUTT05452360    06853080          TC  00WATCH   ENT     D                9908  VKKOPF}
                        //         <- cut
                        sbRecvStr.Remove(0, 4);

                        ItxButton itxButton = ParseButton(sbRecvStr, buttonParseHelper);
                        mapGraphics.Buttons.Add(itxButton);
                        continue;
                    case "RECT":
                        sbRecvStr.Remove(0, 4);
                        elementLength -= 4;
                        ItxRectangle rectangle = ParseGraphicsRectangle(sbRecvStr);
                        mapGraphics.Rectangles.Add(rectangle);
                        sbRecvStr.Remove(0, elementLength);
                        continue;
                        /* listview column rgb colors?!?!? 
                    the colors to color individual cells inside the listview
                    are received here - not inside the listview content or column or somewhere else...*/
                    case "CREC":
                        // remove header
                        sbRecvStr.Remove(0, 4);
                        elementLength -= 4;
                        ItxRectangle cRectangle = ParseGraphicsColoredRectangle(sbRecvStr);
                        mapGraphics.Rectangles.Add(cRectangle);

                        if (elementLength > sbRecvStr.Length)
                            elementLength = sbRecvStr.Length;
                        sbRecvStr.Remove(0, elementLength);
                        continue;
                    case "LINE":
                        sbRecvStr.Remove(0, 4);
                        elementLength -= 4;
                        if (mapGraphics.Lines == null)
                            mapGraphics.Lines = new List<ItxLine>();
                        ItxLine line = ParseLine(sbRecvStr);
                        mapGraphics.Lines.Add(line);
                        sbRecvStr.Remove(0, elementLength);
                        continue;

                    case "LIN1": //ruler
                        sbRecvStr.Remove(0, 4);
                        elementLength -= 4;
                        ItxRuler ruler = ParseRuler(sbRecvStr, elementLength);
                        if (ruler != null)
                        {
                            if (mapGraphics.Rulers == null)
                                mapGraphics.Rulers = new List<ItxRuler>();
                            mapGraphics.Rulers.Add(ruler);
                        }
                        continue;

                    case "TEXT":
                        sbRecvStr.Remove(0, 4);
                        elementLength -= 4;
                        if (mapGraphics.Texts == null)
                            mapGraphics.Texts = new List<ItxTextLabel>();

                        ItxTextLabel textLabel = ParseTexts(sbRecvStr, elementLength, mapGraphics.Rectangles);
                        mapGraphics.Texts.Add(textLabel);
                        continue;
                    case "TACH":
                        sbRecvStr.Remove(0, 4);
                        elementLength -= 4;
                        if (mapGraphics.Gauges == null)
                            mapGraphics.Gauges = new List<ItxGauge>();

                        ItxGauge gauge = ParseGauge(sbRecvStr, elementLength);
                        mapGraphics.Gauges.Add(gauge);
                        continue;
                    case "POLY":
                        sbRecvStr.Remove(0, 4);
                        if (mapGraphics.Polynom == null)
                            mapGraphics.Polynom = new List<ItxPolynom>();

                        ItxPolynom polynom = ParsePolynom(sbRecvStr);
                        mapGraphics.Polynom.Add(polynom);
                        continue;
                    case "ICON":
                        sbRecvStr.Remove(0, 4);
                        elementLength -= 4;
                        ItxIcon icon = ParseIcon(sbRecvStr, elementLength, mapGraphics.Rectangles);
                        if (mapGraphics.Icons == null)
                            mapGraphics.Icons = new List<ItxIcon>();
                        mapGraphics.Icons.Add(icon);
                        continue;
                    case "GM01":
                        mapGraphics.ShowStartBitMap = true;

                        if (elementLength > sbRecvStr.Length)
                            elementLength = sbRecvStr.Length;
                        sbRecvStr.Remove(0, elementLength);
                        continue;
                        // ak91
                    case "KU1 ": // doc states KV
                        // remove header
                        sbRecvStr.Remove(0, 4);
                        elementLength -= 4;

                        MachineUsageParser machineUsageParser = new MachineUsageParser();
                        elementLength = machineUsageParser.ParseMachineUsage(sbRecvStr, mapGraphics, elementLength);

                        if (elementLength > sbRecvStr.Length)
                            elementLength = sbRecvStr.Length;
                        sbRecvStr.Remove(0, elementLength);
                        continue;
                        // av95 - NetzPlan 1
                    case "NP1 ":
                        // remove header
                        sbRecvStr.Remove(0, 4);
                        elementLength -= 4;
                        NetPlanParser netPlanParser = new NetPlanParser();
                        elementLength = netPlanParser.ParseNetPlanData(sbRecvStr, mapGraphics, elementLength);

                        // remove the rest...
                        if (elementLength > sbRecvStr.Length)
                            elementLength = sbRecvStr.Length;
                        sbRecvStr.Remove(0, elementLength);
                        continue;
                    case "PB1 ":
                        // remove header
                        sbRecvStr.Remove(0, 4);
                        elementLength -= 4;
                        PlanBoardParser planBoardParser = new PlanBoardParser();
                        elementLength = planBoardParser.ParsePlanBoard(sbRecvStr, mapGraphics, elementLength);

                        // remove the rest...
                        if (elementLength > sbRecvStr.Length)
                            elementLength = sbRecvStr.Length;
                        sbRecvStr.Remove(0, elementLength);
                        continue;
                    default:
                        if (elementLength > sbRecvStr.Length)
                            elementLength = sbRecvStr.Length;
                        // if elementlength is negativ, just catch it
                        sbRecvStr.Remove(0, elementLength < 0 ? sbRecvStr.Length : elementLength);
                        continue;
                }
            }
            return mapGraphics;
        }


        private static ItxPolynom ParsePolynom(StringBuilder sbRecvStr)
        {
            /* 1
             * 1
             * 179
             * 00
             * 0060
             * 5160
             * 0720
             * 2160
             * 000130065
             * 068119170
             * 03
             * J
             * 07
             * 0000
             * 1TO09829,8T KG202160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216000970
             * 
             * number   1
             * type     1
             * pointcnt 179
             * legendcnt00
             * startx   0060
             * endx     5160
             * starty   0720
             * endy     2160
             * color1   000130065
             * color2   068119170
             * thickness03
             * backcolorJ
             * factor   07
             * texty    0000
             * bcidx    1
             * textTO   TO09829,8T KG
             * rgbnr    2
             * point    0216
             * 0216
             * 0216
             * 0216
             * 0216
             * 0216
             * 0216
             * 0216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216021602160216
             * 0009
             * 70
             */
            ItxPolynom polynom = new ItxPolynom();
            polynom.Number = ParseHelper.String2Int(sbRecvStr.ToString(0, 1));
            polynom.Type = ParseHelper.String2Int(sbRecvStr.ToString(1, 1));
            polynom.PointCount = ParseHelper.String2Int(sbRecvStr.ToString(2, 3));
            polynom.LegendCount = ParseHelper.String2Int(sbRecvStr.ToString(5, 2));
            polynom.StartX = ParseHelper.String2Int(sbRecvStr.ToString(7, 4));
            polynom.EndX = ParseHelper.String2Int(sbRecvStr.ToString(11, 4));
            polynom.StartY = ParseHelper.String2Int(sbRecvStr.ToString(15, 4));
            polynom.EndY = ParseHelper.String2Int(sbRecvStr.ToString(19, 4));
            polynom.Color1 = ParseHelper.String2Color(sbRecvStr.ToString(23, 9));
            polynom.Color2 = ParseHelper.String2Color(sbRecvStr.ToString(32, 9));
            polynom.ThickNess = ParseHelper.String2Int(sbRecvStr.ToString(41, 2));
            polynom.HasBackColor = sbRecvStr.ToString(43, 1) == "J";
            polynom.Factor = ParseHelper.String2Double(sbRecvStr.ToString(44, 2), 1, 1);
            polynom.TextY = ParseHelper.String2Int(sbRecvStr.ToString(46, 4));
            sbRecvStr.Remove(0, 50);
            //elementLength = elementLength - 56;

            int textLength;
            if (sbRecvStr.ToString(0, 2) == "TN")
            {
                textLength = ParseHelper.String2Int(sbRecvStr.ToString(2, 2));
                sbRecvStr.Remove(0, 4);

                if (ComStatics.UseUtf8)
                    polynom.TextName = ParseHelper.ExtractUtf8(textLength, sbRecvStr, true);
                else
                {
                    polynom.TextName = sbRecvStr.ToString(0, textLength);
                    sbRecvStr.Remove(0, textLength);
                }
            }
            polynom.TextNameColorId = ParseHelper.String2Int(sbRecvStr.ToString(0, 1));
            sbRecvStr.Remove(0, 1);

            // re-set identifier
            if (sbRecvStr.ToString(0, 2) == "TO")
            {
                textLength = ParseHelper.String2Int(sbRecvStr.ToString(2, 2));
                sbRecvStr.Remove(0, 4);

                if (ComStatics.UseUtf8)
                    polynom.UpperTextName = ParseHelper.ExtractUtf8(textLength, sbRecvStr, true);
                else
                {
                    polynom.UpperTextName = sbRecvStr.ToString(0, textLength);
                    sbRecvStr.Remove(0, textLength);
                }
            }
            polynom.UpperTextNameColorId = ParseHelper.String2Int(sbRecvStr.ToString(0, 1));
            sbRecvStr.Remove(0, 1);

            // re-set identifier
            if (sbRecvStr.ToString(0, 2) == "TU")
            {
                textLength = ParseHelper.String2Int(sbRecvStr.ToString(2, 2));
                sbRecvStr.Remove(0, 4);

                if (ComStatics.UseUtf8)
                    polynom.LowerTextName = ParseHelper.ExtractUtf8(textLength, sbRecvStr, true);
                else
                {
                    polynom.LowerTextName = sbRecvStr.ToString(0, textLength);
                    sbRecvStr.Remove(0, textLength);
                }
            }
            polynom.LowerTextNameColorId = ParseHelper.String2Int(sbRecvStr.ToString(0, 1));
            sbRecvStr.Remove(0, 1);

            // legends...
            for (int i = 0; i < polynom.LegendCount; i++)
            {
                ItxPolynomLegend polynomLegend = new ItxPolynomLegend();
                if (ComStatics.UseUtf8)
                    polynomLegend.Text = ParseHelper.ExtractUtf8(15, sbRecvStr, true);
                else
                {
                    polynomLegend.Text = sbRecvStr.ToString(0, 15);
                    sbRecvStr.Remove(0, 15);
                }

                polynomLegend.ColorIndex = ParseHelper.String2Int(sbRecvStr.ToString(0, 1));
                polynomLegend.IsVertical = sbRecvStr.ToString(1, 1) == "V";
                polynomLegend.StraightLine = sbRecvStr.ToString(2, 1) == "J";
                polynomLegend.XorY = ParseHelper.String2Int(sbRecvStr.ToString(3, 4));
                polynomLegend.Factor = ParseHelper.String2Double(sbRecvStr.ToString(7, 2), 1, 1);
                sbRecvStr.Remove(0, 9);
            }

            // points...
            for (int i = 0; i < polynom.PointCount; i++)
            {
                int point = ParseHelper.String2Int(sbRecvStr.ToString(0, 4));
                polynom.Points.Add(point);
                sbRecvStr.Remove(0, 4);
            }

            return polynom;
        }

        /// <summary> parse gauges, f.x. ei91
        /// 0210TACH10602102102100806811917010001001001115215940514012800000100100105            10            10RGB1068119170000RGB1000200000100TN21UMSATZ (EUR ) / MONATT105  0,0TM08  2,5T;;TK020%000TK0350%050TK04100%1000
        /// 0218TACH10602102102100806811917010001001001288015940514012800000100100105            10            10RGB1068119170000RGB1000200000100TN29AUFTRAGSEINGANG(EUR) / MONATT105  0,0TM08 24,5T;;TK020%000TK0350%050TK04100%1000
        /// </summary>
        /// <param name="sbRecvStr"></param>
        /// <param name="elementLength"></param>
        /// <returns></returns>
        private static ItxGauge ParseGauge(StringBuilder sbRecvStr, int elementLength)
        {
            /* sample data:
             * 0210TACH
             * type     1
             * size     060
             * ucolor   210210210
             * fontfact 08
             * fontrgb  068119170
             * descfact 10
             * descrgb  001001001
             * centerx  1152
             * centery  1594
             * radius   0514
             * thickness    0128
             * l1perc   000
             * l1color  001001001
             * l1fac    05
             * l2perc  [   ]
             * l2color [         ]
             * l2fac    10
             * l3perc  [   ]
             * l3color [         ]
             * l3fac    10
             * RGB1068119170000RGB1000200000100TN21UMSATZ (EUR ) / MONATT105  0,0TM08  2,5T;;TK020%000TK0350%050TK04100%1000
             */
            ItxGauge gauge = new ItxGauge();
            gauge.Type = sbRecvStr.ToString(0, 1);
            gauge.GaugeCircleSize = ParseHelper.String2Int(sbRecvStr.ToString(1, 3));
            gauge.UndefineColor = ParseHelper.String2Color(sbRecvStr.ToString(4, 9));
            gauge.FontFactor = ParseHelper.String2Double(sbRecvStr.ToString(13, 2), 1, 1);
            gauge.FontColor = ParseHelper.String2Color(sbRecvStr.ToString(15, 9));
            gauge.DescFactor = ParseHelper.String2Double(sbRecvStr.ToString(24, 2), 1, 1);
            gauge.DescRgb = ParseHelper.String2Color(sbRecvStr.ToString(26, 9));
            gauge.CenterX = ParseHelper.String2Int(sbRecvStr.ToString(35, 4));
            gauge.CenterY = ParseHelper.String2Int(sbRecvStr.ToString(39, 4));
            gauge.Radius = ParseHelper.String2Int(sbRecvStr.ToString(43, 4));
            gauge.Thickness = ParseHelper.String2Int(sbRecvStr.ToString(47, 4));

            gauge.Level1Percentage = ParseHelper.String2Int(sbRecvStr.ToString(51, 3));
            gauge.Level1Rgb = ParseHelper.String2Color(sbRecvStr.ToString(54, 9));
            gauge.Level1Factor = ParseHelper.String2Double(sbRecvStr.ToString(63, 2), 1, 1);

            gauge.Level2Percentage = ParseHelper.String2Int(sbRecvStr.ToString(65, 3));
            gauge.Level2Rgb = ParseHelper.String2Color(sbRecvStr.ToString(68, 9));
            gauge.Level2Factor = ParseHelper.String2Double(sbRecvStr.ToString(77, 2), 1, 1);

            gauge.Level3Percentage = ParseHelper.String2Int(sbRecvStr.ToString(79, 3));
            gauge.Level3Rgb = ParseHelper.String2Color(sbRecvStr.ToString(82, 9));
            gauge.Level3Factor = ParseHelper.String2Double(sbRecvStr.ToString(91, 2), 1, 1);

            sbRecvStr.Remove(0, 93);
            elementLength = elementLength - 93;
            while (elementLength > 0)
            {
                string identifier = sbRecvStr.ToString(0, 2);
                elementLength = elementLength - 2;
                sbRecvStr.Remove(0, 2);

                int textLength;
                switch (identifier)
                {
                    case "RG":
                        sbRecvStr.Remove(0, 1); //remove B of RGB
                        ItxGaugeColor gaugeColor = new ItxGaugeColor();
                        gaugeColor.GaugeNo = ParseHelper.String2Int(sbRecvStr.ToString(0, 1));
                        gaugeColor.Color = ParseHelper.String2Color(sbRecvStr.ToString(1, 9));
                        gaugeColor.GaugeMaxPercent = ParseHelper.String2Int(sbRecvStr.ToString(10, 3));
                        gauge.Colors.Add(gaugeColor);

                        sbRecvStr.Remove(0, 13);
                        elementLength = elementLength - 14;
                        break;
                    case "TN":
                        textLength = ParseHelper.String2Int(sbRecvStr.ToString(0, 2));
                        sbRecvStr.Remove(0, 2);

                        if (ComStatics.UseUtf8)
                            gauge.TextName = ParseHelper.ExtractUtf8(textLength, sbRecvStr, true);
                        else
                        {
                            gauge.TextName = sbRecvStr.ToString(0, textLength);
                            sbRecvStr.Remove(0, textLength);
                        }
                        elementLength = elementLength - 2 - textLength;
                        break;
                    case "T1":
                        textLength = ParseHelper.String2Int(sbRecvStr.ToString(0, 2));
                        sbRecvStr.Remove(0, 2);

                        if (ComStatics.UseUtf8)
                            gauge.TextPercent1 = ParseHelper.ExtractUtf8(textLength, sbRecvStr, true);
                        else
                        {
                            gauge.TextPercent1 = sbRecvStr.ToString(0, textLength);
                            sbRecvStr.Remove(0, textLength);
                        }
                        elementLength = elementLength - 2 - textLength;
                        break;
                    case "T2":
                        textLength = ParseHelper.String2Int(sbRecvStr.ToString(0, 2));
                        sbRecvStr.Remove(0, 2);

                        if (ComStatics.UseUtf8)
                            gauge.TextPercent2 = ParseHelper.ExtractUtf8(textLength, sbRecvStr, true);
                        else
                        {
                            gauge.TextPercent2 = sbRecvStr.ToString(0, textLength);
                            sbRecvStr.Remove(0, textLength);
                        }
                        elementLength = elementLength - 2 - textLength;
                        break;
                    case "T3":
                        textLength = ParseHelper.String2Int(sbRecvStr.ToString(0, 2));
                        sbRecvStr.Remove(0, 2);

                        if (ComStatics.UseUtf8)
                            gauge.TextPercent3 = ParseHelper.ExtractUtf8(textLength, sbRecvStr, true);
                        else
                        {
                            gauge.TextPercent3 = sbRecvStr.ToString(0, textLength);
                            sbRecvStr.Remove(0, textLength);
                        }
                        elementLength = elementLength - 2 - textLength;
                        break;
                    case "TM":
                        textLength = ParseHelper.String2Int(sbRecvStr.ToString(0, 2));
                        sbRecvStr.Remove(0, 2);

                        if (ComStatics.UseUtf8)
                            gauge.CenterText = ParseHelper.ExtractUtf8(textLength, sbRecvStr, true);
                        else
                        {
                            gauge.CenterText = sbRecvStr.ToString(0, textLength);
                            sbRecvStr.Remove(0, textLength);
                        }
                        elementLength = elementLength - 2 - textLength;
                        break;
                    case "TB":
                        textLength = ParseHelper.String2Int(sbRecvStr.ToString(0, 2));
                        sbRecvStr.Remove(0, 2);

                        if (ComStatics.UseUtf8)
                            gauge.CenterBitMap = ParseHelper.ExtractUtf8(textLength, sbRecvStr, true);
                        else
                        {
                            gauge.CenterBitMap = sbRecvStr.ToString(0, textLength);
                            sbRecvStr.Remove(0, textLength);
                        }
                        elementLength = elementLength - 2 - textLength;
                        break;
                    case "TK":
                        textLength = ParseHelper.String2Int(sbRecvStr.ToString(0, 2));
                        sbRecvStr.Remove(0, 2);

                        if (ComStatics.UseUtf8)
                            gauge.CircleText = ParseHelper.ExtractUtf8(textLength, sbRecvStr, true);
                        else
                        {
                            gauge.CircleText = sbRecvStr.ToString(0, textLength);
                            sbRecvStr.Remove(0, textLength);
                        }
                        // add property
                        gauge.CircleTextPercent = ParseHelper.String2Int(sbRecvStr.ToString(0, 3));
                        sbRecvStr.Remove(0, 3);

                        elementLength = elementLength - 5 - textLength;
                        break;
                }

            }
            return gauge;
        }

        private static void ParseContextMenu(StringBuilder sbRecvStr, MapGraphics mapGraphics, int elementLength)
        {
            // parse content
            string entry;
            if (ComStatics.UseUtf8)
                entry = ParseHelper.ExtractUtf8(elementLength, sbRecvStr, true);
            else
            {
                entry = sbRecvStr.ToString(0, elementLength);
                sbRecvStr.Remove(0, elementLength);
            }

            // if we have a vm with info we have an !=I instat of an == I
            entry = entry.Replace("!", "=");

            string[] values = entry.Split(new[] {"=="}, StringSplitOptions.None);
            if (values.Length <= 1)
                return;
            values[0] = values[0].Replace('#', ' ');
            if (values[1][values[1].Length - 1] == ';')
                values[1] = values[1].Remove(values[1].Length - 1);
            mapGraphics.ContextMenu.Entrys.Add(new ItxContextMenuItem(values[0], values[1]));
        }

        private static void ParseBitmap(StringBuilder sbRecvStr, MapGraphics mapGraphics)
        {
            /* Start-Y		9(04) in Pseudopixeln
             * Start-X		9(04) in Pseudopixeln
             * Ende-Y		9(04) in Pseudopixeln
             * Ende-X		9(04) in Pseudopixeln
             * Farbe		9(04) 9999=transparent; 9998=transparent Icon
             * Prop		    X(01) proportional. 
             *                  J=die Seitenverhältnisse bleiben erhalten (ohne zu kappen);
             *                  F=BMP wird in die Fläche gestrecht (full); 
             *                  sonst einfach rein in die Fläche…
             * Orientierung	9(03) (ohne Bedeutung)
             * Bezug		X(01) (ohne Bedeutung)
             * Reserve		X(32)
             * BMP-File	X(256)
             * Pflicht		X(01) J=ist das BMP nicht vorhanden, so wird nur ein Rahmen gemalt
             * [11233750276499980000J000                                  c:\intex.nt\intex\pic\user\00000001.!!!                                                                                                                                                                                                                         J]
            */
            ItxBitmap itxBitmap = new ItxBitmap
                {
                    Top = ParseHelper.String2Int(sbRecvStr.ToString(0, 4)),
                    Left = ParseHelper.String2Int(sbRecvStr.ToString(4, 4))
                };

            sbRecvStr.Remove(0, 8);

            // pos3/4
            itxBitmap.Bottom = ParseHelper.String2Int(sbRecvStr.ToString(0, 4));
            itxBitmap.Right = ParseHelper.String2Int(sbRecvStr.ToString(4, 4));
            sbRecvStr.Remove(0, 8);

            string color = sbRecvStr.ToString(0, 4);
            itxBitmap.Transparent = color == "9999" || color == "9998";
            switch (sbRecvStr[4])
            {
                case 'J':
                    itxBitmap.Stretching = ItxBitmapFill.Proportional;
                    break;
                case 'F':
                    itxBitmap.Stretching = ItxBitmapFill.Stretch;
                    break;
                default:
                    itxBitmap.Stretching = ItxBitmapFill.JustInsert;
                    break;
            }

            // remove
            sbRecvStr.Remove(0, 42);

            int sourceLength = 256;
            if (sbRecvStr.Length < 256)
                sourceLength = sbRecvStr.Length;

            string source;
            if (ComStatics.UseUtf8)
                source = ParseHelper.ExtractUtf8(sourceLength, sbRecvStr, true);
            else
            {
                source = sbRecvStr.ToString(0, sourceLength);
                sbRecvStr.Remove(0, sourceLength);
            }
            itxBitmap.Source = source.TrimEnd();

            // cut rest
            if (sbRecvStr.Length == 0)
                itxBitmap.DisplayAlways = false;
            else
            {
                itxBitmap.DisplayAlways = sbRecvStr[0] == 'J';
                sbRecvStr.Remove(0, 1);
            }

            // return value
            if (mapGraphics.BitMap == null)
                mapGraphics.BitMap = new List<ItxBitmap>();
            mapGraphics.BitMap.Add(itxBitmap);
        }

        private static ItxButton ParseButton(StringBuilder sbRecvStr, ButtonParseHelper buttonParseHelper)
        {
            // pos1
            ItxButton itxButton = new ItxButton(ItxHorizontalAlignment.Left)
                {
                    Top = ParseHelper.String2Int(sbRecvStr.ToString(0, 4)),
                    Left = ParseHelper.String2Int(sbRecvStr.ToString(4, 4))
                };

            // filler of 4
            sbRecvStr.Remove(0, 12);

            // pos3/4
            itxButton.Bottom = ParseHelper.String2Int(sbRecvStr.ToString(0, 4));
            itxButton.Right = ParseHelper.String2Int(sbRecvStr.ToString(4, 4));

            // filler of 4
            sbRecvStr.Remove(0, 12);
            //00100BUTT10801380    12423300          R5  00FC      ENT     V                7018    V    = Versand
            //                                 <- cut

            // cut additional 12 due to unkown
            sbRecvStr.Remove(0, 10);
            //00100BUTT10801380    12423300          R5  00FC      ENT     V                7018    V    = Versand
            //                                           <- cut

            // button no
            itxButton.ButtonNo = ParseHelper.String2Int(sbRecvStr.ToString(0, 2));
            sbRecvStr.Remove(0, 2);

            // field for action
            string field = sbRecvStr.ToString(0, 8).Trim();
            sbRecvStr.Remove(0, 8);

            // cut whatever
            itxButton.ActionType = buttonParseHelper.ParseAction(sbRecvStr.ToString(0, 8));
            sbRecvStr.Remove(0, 8);
            //00100BUTT10801380    12423300          R5  00FC      ENT     V                7018    V    = Versand
            //                                                             <- cut

            // field content
            string value;
            if (ComStatics.UseUtf8)
                value = ParseHelper.ExtractUtf8(17, sbRecvStr, true);
            else
            {
                value = sbRecvStr.ToString(0, 17);
                sbRecvStr.Remove(0, 17);
            }

            // 7? :D TODO
            //string seven = sbRecvStr.ToString(0,1);

            // following content length
            int contentLength = ParseHelper.String2Int(sbRecvStr.ToString(2, 2));
            sbRecvStr.Remove(0, 4);

            // the content has 2 spaces preceeding defining an icon
            itxButton.Icon = sbRecvStr.ToString(0, 2);
            sbRecvStr.Remove(0, 2);

            // subtract 2 from contentLength
            contentLength -= 2;

            // now the text
            if (ComStatics.UseUtf8)
                itxButton.Text = ParseHelper.ExtractUtf8(contentLength, sbRecvStr, true);
            else
            {
                itxButton.Text = sbRecvStr.ToString(0, contentLength);
                sbRecvStr.Remove(0, contentLength);
            }

            // build action
            ItxButtonAction buttonAction = new ItxButtonAction(field, value, itxButton.ActionType);
            itxButton.Actions.Add(buttonAction);
            itxButton.AssignedField = field;

            return itxButton;
        }

        private static ItxRectangle ParseGraphicsRectangle(StringBuilder sbRecvStr)
        {
            return new ItxRectangle(ItxRectangleType.Graphics)
                {
                    StartY = ParseHelper.String2Int(sbRecvStr.ToString(0, 4)),
                    StartX = ParseHelper.String2Int(sbRecvStr.ToString(4, 4)),
                    EndY = ParseHelper.String2Int(sbRecvStr.ToString(8, 4)),
                    EndX = ParseHelper.String2Int(sbRecvStr.ToString(12, 4)),
                    ColorNo = ParseHelper.String2Int(sbRecvStr.ToString(16, 4)),
                    Gradient = sbRecvStr.ToString(20, 2),
                    BorderType = sbRecvStr.ToString(22, 2),
                    IsFixed = sbRecvStr.ToString(24, 2) == "J",
                };
        }

        private static ItxRectangle ParseGraphicsColoredRectangle(StringBuilder sbRecvStr)
        {
            /*  00038CREC0000000000000000128000255  2
                00038CREC0000000000000000128000255  2
                00038CREC0000000000000000128000255  2
                00038CREC0000000000000000001001001  2
                00038CREC0000000000000000001001001  2
                00038CREC0000000000000000001001001  2
                00038CREC0000000000000000001001001  2*/
            ItxRectangle cRectangle = new ItxRectangle(ItxRectangleType.GraphicsColored)
                {
                    StartY = ParseHelper.String2Int(sbRecvStr.ToString(0, 4)),
                    StartX = ParseHelper.String2Int(sbRecvStr.ToString(4, 4)),
                    EndY = ParseHelper.String2Int(sbRecvStr.ToString(8, 4)),
                    EndX = ParseHelper.String2Int(sbRecvStr.ToString(12, 4)),
                    RgbColorString = sbRecvStr.ToString(16, 9),
                    Gradient = sbRecvStr.ToString(25, 2)
                };

            cRectangle.IsDummyRectangle = cRectangle.StartY == 0 && cRectangle.StartX == 0 && cRectangle.EndX == 0 && cRectangle.EndY == 0;
            return cRectangle;
        }

        /// <summary>
        /// Element-Typ = LIN1  Lineal
        /// Von-y		9(04)		in Pseudo-Koordinaten(1x= 60 1y= 180)
        /// Von-x		9(04)
        /// Bis-y		9(04)
        /// Bis-x		9(04)
        /// Typ X(02)       not used
        /// Rahmen X(02)       1=einfach, 1W=einf.white, 2=zweifach, 2+=zweif.hoch, 2-=zweif.tief, usw.
        /// Reset X(01)       not used
        /// Feld1 X(08)       not used
        /// Feld2 X(08)       not used
        /// Feld3 X(08)       not used
        /// Feld4 X(08)       not used
        /// Feld5 X(08)       not used
        /// Raster-Typ X(01)       not used
        /// Wert-0		9(05)V9(03) Lineal von
        /// Wert-1		9(05)V9(03) Lineal bis
        /// ABS-Rast	9(05)V9(03) Abstand der Rasterung in Spalten
        /// ABS-Leg		9(05)V9(03) Abstand dicke Rasterung(3=alle 3 kleinen Striche ein dicker Strich)
        /// ABS-Zone	9(05)V9(03) not used
        /// Leg-Höhe	9(03)		not used
        /// RGB-Hinten	9(09)		not used
        /// .RGB-Vorne  9(09)       Vordergrundfarbe
        /// .RGB-not-used	9(09)		not used
        /// Strich-Breite	9(04)		dicker Strich in Pseudopixel
        /// Strich-Höhe	9(04)		dicker Strich in Pseudopixel
        /// Strich-Breite	9(04)		not used
        /// Strich-Höhe	9(04)		not used
        /// Strich-Breite	9(03)		dünner Strich in Pseudopixel
        /// Strich-Höhe	9(03)		dünner Strich in Pseudopixel
        /// -Strich-Basis	9(03)		der Lineal-Strich in Pseudopixel
        /// </summary>
        /// <param name="sbRecvStr"></param>
        /// <param name="elementLength"></param>
        /// <returns></returns>
        private static ItxRuler ParseRuler(StringBuilder sbRecvStr, int elementLength)
        {
            if (elementLength <= 0)
                return null;

            ItxRuler ruler = new ItxRuler
                {
                    StartY = ParseHelper.String2Int(sbRecvStr.ToString(0, 4)),
                    StartX = ParseHelper.String2Int(sbRecvStr.ToString(4, 4)),
                    EndY = ParseHelper.String2Int(sbRecvStr.ToString(8, 4)),
                    EndX = ParseHelper.String2Int(sbRecvStr.ToString(12, 4))
                };

            // type not used +2
            sbRecvStr.Remove(0, 18);
            elementLength = elementLength - 18;
            ruler.BorderType = sbRecvStr.ToString(0, 2);
            //reset 
            //field1
            //field2
            //field3
            //field4
            //field5
            //raster type
            sbRecvStr.Remove(0, 44);
            elementLength = elementLength - 44;
            ruler.RulerStart = ParseHelper.String2Double(sbRecvStr.ToString(0, 8), 5, 3);
            ruler.RulerEnd = ParseHelper.String2Double(sbRecvStr.ToString(8, 8), 5, 3);
            ruler.RulerDifference = ParseHelper.String2Double(sbRecvStr.ToString(16, 8), 5, 3);
            ruler.RulerFatDifference = ParseHelper.String2Double(sbRecvStr.ToString(24, 8), 5, 3);
            sbRecvStr.Remove(0, 32);
            elementLength = elementLength - 32;
            //abs-zone
            //leg-hoehe
            //rgb-back
            sbRecvStr.Remove(0, 20);
            elementLength = elementLength - 20;
            ruler.ForeColor = ParseHelper.String2Color(sbRecvStr.ToString(0, 9));
            //rgb-not-used
            sbRecvStr.Remove(0, 18);
            elementLength = elementLength - 18;
            ruler.ThickStrokeWeight = ParseHelper.String2Int(sbRecvStr.ToString(0, 4));
            ruler.ThickStrokeHeight = ParseHelper.String2Int(sbRecvStr.ToString(4, 4));
            //strich-breite
            //strich-hoehe
            sbRecvStr.Remove(0, 16);
            elementLength = elementLength - 16;
            ruler.ThinStrokeWeight = ParseHelper.String2Int(sbRecvStr.ToString(0, 3));
            ruler.ThinStrokeHeight = ParseHelper.String2Int(sbRecvStr.ToString(3, 3));
            ruler.StrokeBase = ParseHelper.String2Int(sbRecvStr.ToString(6, 3));
            sbRecvStr.Remove(0, 9);
            elementLength = elementLength - 9;

            // cut rest
            if (elementLength > 0)
                sbRecvStr.Remove(0, elementLength);
            return ruler;
        }

        private static ItxLine ParseLine(StringBuilder sbRecvStr)
        {
            ItxLine line = new ItxLine
                {
                    StartY = ParseHelper.String2Int(sbRecvStr.ToString(0, 4)),
                    StartX = ParseHelper.String2Int(sbRecvStr.ToString(4, 4)),
                    EndY = ParseHelper.String2Int(sbRecvStr.ToString(8, 4)),
                    EndX = ParseHelper.String2Int(sbRecvStr.ToString(12, 4)),
                    ColorNo = ParseHelper.String2Int(sbRecvStr.ToString(16, 4))
                };
            //optional
            if (sbRecvStr.Length <= 25)
                return line;

            line.Thickness = sbRecvStr.ToString(22, 1);
            line.BorderType = sbRecvStr.ToString(23, 2);

            return line;
        }

        private static ItxTextLabel ParseTexts(StringBuilder sbRecvStr, int elementLength, List<ItxRectangle> parsedColorRectangles)
        {
            /* sample:  TEXT0580 1550 0130 2150 0001Y000  Area            
             *     00051TEXT0580 2090 0130 2690 0001Y000  Woche
             *              09210101009005310001E000  1001/ 1 RASCHEL
             *     0051TEXT11010101009005310001E000  1002/ 1 RASCHEL }
             *     el  id  |sy||sx||he||wi|
             *             1101    0090    
             *                 0101    0531
             * vony    0580    vonx    1550     bisy    0130    bisx    2150
             * farbnr  0001     prop    y       
             * Element-Typ = TEXT      Freitext
             * Von-y		    9(04)	in Pseudo-Koordinaten (1x=60 1y=180)
             * Von-x		    9(04)
             * Bis-y		    9(04) height
             * Bis-x		    9(04) width
             * FarbNr		    9(04)
             * Prop		    X(01)	Schrift (M = Font fürs Planbord; E, Y = Eingabefont; A = Konstantenfont; sonst = fixed Font)
             * orientierung   9(03)
             * ausrichtung    x(03)
             * Text		    X(var) */
            ItxTextLabel textLabel = new ItxTextLabel
                {
                    StartY = ParseHelper.String2Int(sbRecvStr.ToString(0, 4)),
                    StartX = ParseHelper.String2Int(sbRecvStr.ToString(4, 4)),
                    Height = ParseHelper.String2Int(sbRecvStr.ToString(8, 4)),
                    Width = ParseHelper.String2Int(sbRecvStr.ToString(12, 4)),
                    ColorNo = ParseHelper.String2Int(sbRecvStr.ToString(16, 4)),
                    Property = sbRecvStr.ToString(20, 1),
                    Orientation = ParseHelper.String2Int(sbRecvStr.ToString(21, 3)),
                    AlignmentStr = sbRecvStr.ToString(24, 2)
                };

            // if we receive x/y zero then we need to check for the last rectangle (CREC)
            if (textLabel.Width == 0 && textLabel.Height == 0 && textLabel.StartY == 0 && textLabel.StartX == 0
                && parsedColorRectangles.Count > 0)
            {
                textLabel.LinkedColorRectangleIndex = parsedColorRectangles.Count - 1;

                var lastRectangle = parsedColorRectangles[textLabel.LinkedColorRectangleIndex];
                textLabel.StartY = lastRectangle.StartY;
                textLabel.StartX = lastRectangle.StartX;
                textLabel.Width = lastRectangle.EndX - lastRectangle.StartX;
                textLabel.Height = lastRectangle.EndY - lastRectangle.StartY;
            }

            // verify elementlength (may happen if no further data are available after this section)
            if (sbRecvStr.Length < elementLength)
            {
                if (ComStatics.UseUtf8)
                    textLabel.Text = ParseHelper.ExtractUtf8(sbRecvStr.Length - 26, sbRecvStr, true);
                else
                {
                    textLabel.Text = sbRecvStr.ToString(26, sbRecvStr.Length - 26);
                    sbRecvStr.Remove(0, sbRecvStr.Length);
                }
            }
            else
            {
                if (ComStatics.UseUtf8)
                    textLabel.Text = ParseHelper.ExtractUtf8(elementLength - 26, sbRecvStr, true);
                else
                {
                    textLabel.Text = sbRecvStr.ToString(26, elementLength - 26);
                    sbRecvStr.Remove(0, elementLength);
                }
            }

            return textLabel;
        }

        private static ItxIcon ParseIcon(StringBuilder sbRecvStr, int elementLength, List<ItxRectangle> parsedColorRectangles)
        {
            /* */
            ItxIcon icon = new ItxIcon
                {
                    EndY = ParseHelper.String2Int(sbRecvStr.ToString(0, 4)),
                    StartX = ParseHelper.String2Int(sbRecvStr.ToString(4, 4)),
                    StartY = ParseHelper.String2Int(sbRecvStr.ToString(8, 4)),
                    EndX = ParseHelper.String2Int(sbRecvStr.ToString(12, 4))
                };

            // if we receive x/y zero then we need to check for the last rectangle (CREC)
            if (icon.EndX == 0 && icon.EndY == 0 && icon.StartY == 0 && icon.StartX == 0
                && parsedColorRectangles.Count > 0)
            {
                icon.LinkedColorRectangleIndex = parsedColorRectangles.Count - 1;

                var lastRectangle = parsedColorRectangles[icon.LinkedColorRectangleIndex];
                icon.StartY = lastRectangle.StartY;
                icon.EndX = lastRectangle.EndX;
                icon.EndY = lastRectangle.EndY;
                icon.StartX = lastRectangle.StartX;
            }

            // verify elementlength (may happen if no further data are available after this section)
            string name;
            if (ComStatics.UseUtf8)
                name = ParseHelper.ExtractUtf8(elementLength - 16, sbRecvStr, true);
            else
            {
                name = sbRecvStr.ToString(16, elementLength - 16);
                sbRecvStr.Remove(0, elementLength);
            }

            // check for alignment inside name
            if (name.Contains(";"))
            {
                string[] splittedName = name.Split(';');
                icon.Name = splittedName[0];
                switch (splittedName[1].Trim())
                {
                    case "1":
                        icon.Alignment = ItxAlignment.Left;
                        break;
                    case "5":
                        icon.Alignment = ItxAlignment.Middle;
                        break;
                    case "9":
                        icon.Alignment = ItxAlignment.Right;
                        break;
                }
            }
            else
                icon.Name = name;

            return icon;
        }
    }
}